import {Server} from 'socket.io'
import pathfinding from 'pathfinding'

const origin = process.env.CLIENT_URL || 'http://localhost:5173'
const io = new Server({
  cors: {
    origin
  }
})

const host = process.env.HOST || 'localhost'
const port = process.env.PORT || 3000
io.listen(Number(port))

console.log(`Server started on http://${host}:${port}, allowed cors origin: ${origin}`)


const characters = []

const items = {
  washer: {
    name: 'washer',
    size: [2, 2]
  },
  toiletSquare: {
    name: 'toiletSquare',
    size: [2, 2]
  },
  trashcan: {
    name: 'trashcan',
    size: [1, 1]
  },
  bathroomCabinetDrawer: {
    name: 'bathroomCabinetDrawer',
    size: [2, 2]
  },
  bathtub: {
    name: 'bathtub',
    size: [4, 2]
  },
  bathroomMirror: {
    name: 'bathroomMirror',
    size: [2, 1],
    wall: true
  },
  bathroomCabinet: {
    name: 'bathroomCabinet',
    size: [2, 1],
    wall: true
  },
  bathroomSink: {
    name: 'bathroomSink',
    size: [2, 2]
  },
  showerRound: {
    name: 'showerRound',
    size: [2, 2]
  },
  tableCoffee: {
    name: 'tableCoffee',
    size: [4, 2]
  },
  loungeSofaCorner: {
    name: 'loungeSofaCorner',
    size: [5, 5]
  },
  bear: {
    name: 'bear',
    size: [2, 1],
    wall: true
  },
  loungeSofaOttoman: {
    name: 'loungeSofaOttoman',
    size: [2, 2]
  },
  tableCoffeeGlassSquare: {
    name: 'tableCoffeeGlassSquare',
    size: [2, 2]
  },
  loungeDesignSofaCorner: {
    name: 'loungeDesignSofaCorner',
    size: [5, 5]
  },
  loungeDesignSofa: {
    name: 'loungeDesignSofa',
    size: [5, 2]
  },
  loungeSofa: {
    name: 'loungeSofa',
    size: [5, 2]
  },
  bookcaseOpenLow: {
    name: 'bookcaseOpenLow',
    size: [2, 1]
  },
  kitchenBar: {
    name: 'kitchenBar',
    size: [2, 1]
  },
  bookcaseClosedWide: {
    name: 'bookcaseClosedWide',
    size: [3, 1]
  },
  bedSingle: {
    name: 'bedSingle',
    size: [3, 5]
  },
  bench: {
    name: 'bench',
    size: [2, 1]
  },
  bedDouble: {
    name: 'bedDouble',
    size: [5, 5]
  },
  benchCushionLow: {
    name: 'benchCushionLow',
    size: [2, 1]
  },
  loungeChair: {
    name: 'loungeChair',
    size: [2, 2]
  },
  cabinetBedDrawer: {
    name: 'cabinetBedDrawer',
    size: [1, 1]
  },
  cabinetBedDrawerTable: {
    name: 'cabinetBedDrawerTable',
    size: [1, 1]
  },
  table: {
    name: 'table',
    size: [4, 2]
  },
  tableCrossCloth: {
    name: 'tableCrossCloth',
    size: [4, 2]
  },
  plant: {
    name: 'plant',
    size: [1, 1]
  },
  plantSmall: {
    name: 'plantSmall',
    size: [1, 1]
  },
  rugRounded: {
    name: 'rugRounded',
    size: [6, 4],
    walkable: true
  },
  rugRound: {
    name: 'rugRound',
    size: [4, 4],
    walkable: true
  },
  rugSquare: {
    name: 'rugSquare',
    size: [4, 4],
    walkable: true
  },
  rugRectangle: {
    name: 'rugRectangle',
    size: [8, 4],
    walkable: true
  },
  televisionVintage: {
    name: 'televisionVintage',
    size: [4, 2]
  },
  televisionModern: {
    name: 'televisionModern',
    size: [4, 2]
  },
  kitchenCabinetCornerRound: {
    name: 'kitchenCabinetCornerRound',
    size: [2, 2]
  },
  kitchenCabinetCornerInner: {
    name: 'kitchenCabinetCornerInner',
    size: [2, 2]
  },
  kitchenCabinet: {
    name: 'kitchenCabinet',
    size: [2, 2]
  },
  kitchenBlender: {
    name: 'kitchenBlender',
    size: [1, 1]
  },
  dryer: {
    name: 'dryer',
    size: [2, 2]
  },
  chairCushion: {
    name: 'chairCushion',
    size: [1, 1]
  },
  chair: {
    name: 'chair',
    size: [1, 1]
  },
  deskComputer: {
    name: 'deskComputer',
    size: [3, 2]
  },
  desk: {
    name: 'desk',
    size: [3, 2]
  },
  chairModernCushion: {
    name: 'chairModernCushion',
    size: [1, 1]
  },
  chairModernFrameCushion: {
    name: 'chairModernFrameCushion',
    size: [1, 1]
  },
  kitchenMicrowave: {
    name: 'kitchenMicrowave',
    size: [1, 1]
  },
  coatRackStanding: {
    name: 'coatRackStanding',
    size: [1, 1]
  },
  kitchenSink: {
    name: 'kitchenSink',
    size: [2, 2]
  },
  lampRoundFloor: {
    name: 'lampRoundFloor',
    size: [1, 1]
  },
  lampRoundTable: {
    name: 'lampRoundTable',
    size: [1, 1]
  },
  lampSquareFloor: {
    name: 'lampSquareFloor',
    size: [1, 1]
  },
  lampSquareTable: {
    name: 'lampSquareTable',
    size: [1, 1]
  },
  toaster: {
    name: 'toaster',
    size: [1, 1]
  },
  kitchenStove: {
    name: 'kitchenStove',
    size: [2, 2]
  },
  laptop: {
    name: 'laptop',
    size: [1, 1]
  },
  radio: {
    name: 'radio',
    size: [1, 1]
  },
  speaker: {
    name: 'speaker',
    size: [1, 1]
  },
  speakerSmall: {
    name: 'speakerSmall',
    size: [1, 1]
  },
  stoolBar: {
    name: 'stoolBar',
    size: [1, 1]
  },
  stoolBarSquare: {
    name: 'stoolBarSquare',
    size: [1, 1]
  }
}

const map = {
  girdSize: [10, 10],
  girdSpace: 2,
  items: [
    {
      ...items.showerRound,
      position: [0, 0],
    },
    {
      ...items.toiletSquare,
      position: [0, 3],
      rotation: 1,
    },
    {
      ...items.washer,
      position: [5, 0],
    },
    {
      ...items.bathroomSink,
      position: [7, 0],
    },
    {
      ...items.trashcan,
      position: [0, 5],
      rotation: 1,
    },
    {
      ...items.bathroomCabinetDrawer,
      position: [3, 0],
    },
    {
      ...items.bathtub,
      position: [4, 4],
    },
    {
      ...items.bathtub,
      position: [0, 8],
      rotation: 3,
    },
    {
      ...items.bathroomCabinet,
      position: [3, 0],
    },
    {
      ...items.bathroomMirror,
      position: [0, 8],
      rotation: 1,
    },
    {
      ...items.bathroomMirror,
      position: [, 10],
      rotation: 1,
    },
    {
      ...items.tableCoffee,
      position: [10, 8],
    },
    {
      ...items.rugRectangle,
      position: [8, 7],
    },
    {
      ...items.loungeSofaCorner,
      position: [6, 10],
    },
    {
      ...items.bear,
      position: [0, 3],
      rotation: 1,
    },
    {
      ...items.plant,
      position: [11, 13],
    },
    {
      ...items.cabinetBedDrawerTable,
      position: [13, 19],
    },
    {
      ...items.cabinetBedDrawer,
      position: [19, 19],
    },
    {
      ...items.bedDouble,
      position: [14, 15],
    },
    {
      ...items.bookcaseClosedWide,
      position: [12, 0],
      rotation: 2,
    },
    {
      ...items.speaker,
      position: [11, 0],
    },
    {
      ...items.speakerSmall,
      position: [15, 0],
    },
    {
      ...items.loungeChair,
      position: [10, 4],
    },
    {
      ...items.loungeSofaOttoman,
      position: [14, 4],
    },
    {
      ...items.loungeDesignSofa,
      position: [18, 0],
      rotation: 1,
    },
    {
      ...items.kitchenCabinetCornerRound,
      position: [2, 18],
      rotation: 2,
    },
    {
      ...items.kitchenCabinetCornerInner,
      position: [0, 18],
      rotation: 2,
    },
    {
      ...items.kitchenStove,
      position: [0, 16],
      rotation: 1,
    },
    {
      ...items.dryer,
      position: [0, 14],
      rotation: 1,
    },
    {
      ...items.lampRoundFloor,
      position: [0, 12],
    },
  ],
}

const grid = new pathfinding.Grid(
  map.girdSize[0] * map.girdSpace,
  map.girdSize[1] * map.girdSpace,
)

const finder = new pathfinding.AStarFinder({
  allowDiagonal: true,
  dontCrossCorners: true
})

const findPath = (start, end) => {
  const copy = grid.clone()
  return finder.findPath(
    start[0], start[1],
    end[0], end[1],
    copy
  )
}

// console.log(findPath([3, 3], [4, 7]))

const updateGrid = () => {
  // 重置网格到初始化状态
  for (let x = 0; x < map.girdSize[0] * map.girdSpace; x++) {
    for (let y = 0; y < map.girdSize[1] * map.girdSpace; y++) {
      grid.setWalkableAt(x,y,true)
    }
  }

  map.items.forEach(item => {
    const {walkable, wall, size, rotation, position} = item
    if (walkable || wall) return
    const width = (rotation === 1 || rotation === 3) ? size[1] : size[0]
    const height = (rotation === 1 || rotation === 3) ? size[0] : size[1]
    for (let x = 0; x < width; x++) {
      for (let y = 0; y < height; y++) {
        grid.setWalkableAt(
          position[0] + x,
          position[1] + y,
          false
        )
      }
    }
  })
}


io.on('connection', (socket) => {
  console.log('user connected')

  characters.push({
    id: socket.id,
    position: generateRandomPosition(),
    hairColor: generateRandomHexColor(),
    topColor: generateRandomHexColor(),
    bottomColor: generateRandomHexColor(),
    avatarUrl: 'https://models.readyplayer.me/65d75aae54d1a2d49d6c4076.glb'
  })

  socket.emit('hello', {
    map,
    characters,
    items,
    id: socket.id
  })

  io.emit('characters', characters)

  socket.on('move', (from, to) => {
    // console.log(pos)
    // console.log(from, to)
    const character = characters.find(c => c.id === socket.id)

    const path = findPath(from, to)
    if (!path) {
      console.log(socket.id + ': 没有找到路')
      return
    }

    character.position = from
    character.path = path

    // console.log(path)

    // character.position = pos
    // characters.forEach(c => {
    //   if (c.id === socket.id) {
    //     c.position = pos
    //   }
    // })
    // io.emit('characters', characters)
    io.emit('player-move', character)
  })

  socket.on('character-dance', () => {
    io.emit('characters-dance', {
      id: socket.id
    })
  })

  // 用户设置角色更新
  socket.on('character-avatar-update', avatarUrl => {
    const character = characters.find(c => c.id === socket.id)
    character.avatarUrl = avatarUrl.split('?')[0] + '?' + new Date().getTime()
    io.emit('characters', characters)
  })

  // items 更新
  socket.on('items-update', (items) => {
    map.items = items
    // 所有的人物重置
    characters.forEach((character) => {
      // 重置路径
      character.path = []
      character.position = generateRandomPosition()
    })
    // 重新更新网格路径
    updateGrid()
    // 通知客户端
    io.emit('map-update', {
      map,
      characters
    })
  })

  socket.on('disconnect', () => {
    console.log('user disconnected')

    characters.splice(
      characters.findIndex((character) => character.id === socket.id), 1
    )
    io.emit('characters', characters)
  })
})

updateGrid()
// console.log(findPath([0, 0], [0, 5]))
// console.log(findPath([3, 3], [4, 7]))

const generateRandomPosition = () => {
  const {girdSize, girdSpace} = map
  for (let i = 0; i < 100; i++) {
    const x = Math.floor(Math.random() * girdSize[0] * girdSpace)
    const z = Math.floor(Math.random() * girdSize[1] * girdSpace)
    if (grid.isWalkableAt(x, z)) {
      return [x ,z]
    }
  }
  const x = Math.floor(Math.random() * girdSize[0] * girdSpace)
  const z = Math.floor(Math.random() * girdSize[1] * girdSpace)
  return [x ,z]
}

const generateRandomHexColor = () => {
  return '#' + Math.floor(Math.random() * 16777215).toString(16)
}
